package ferp.android;

import android.view.MenuItem;
import ferp.android.activities.Ferp;
import ferp.android.services.IResolverService2;
import ferp.android.tasks.local.TaskGameResume;
import ferp.android.views.TableView;
import ferp.core.card.Card;
import ferp.core.game.Game;
import ferp.core.game.Settings;
import ferp.core.game.Trick;
import ferp.core.mode.Mode;
import ferp.core.mode.Moving;
import ferp.core.player.Player;
import ferp.core.state.State;

/**
 * User: olegs
 * Date: 2/6/13 5:42 PM
 */
public class RestoreGame
{
  /*
   * todo: consider moving the code to state.Resume adding required methods to the game listener and calling
   *       listener.onGameResumeRequested() which would execute the TaskGameResume
   */
  public static void execute(Ferp ferp, Game g, Settings settings, IResolverService2 service, TableView table, MenuItem lastTrick)
  {
    boolean moving = Mode.isMoving(g.mode());

    restoreLastTrickMenu(g, lastTrick);
    restoreFirstHand(g, table);
    restorePlayers(g, settings, table, moving);
    restoreTalon(g, settings, table);

    //  the game can be in the "ShowPool2" state when the play was ended early (offers)
    if (g.state() == State.showPool2)
    {
      g.options.clear();

      g.set(State.showPool1);
    }

    // Note: this is for compliance with the old "game save" implementation
    if (g.state() == State.showPool1 || g.state() == State.end || g.state() == State.fastMoving || g.state() == State.showInitialPosition)
    {
      ferp.onGameResumeFinished(g);

      return;
    }
    // end of compliance block

    if (moving && g.state() != State.initialize)
    {
      // adjust round number as its value may remain from the previous mode (we did not go through Mode.initialize)
      g.rounds = g.trick.list().size();

      restoreMisere(g, settings, table);
      restoreTrick(g, table);

      // start game resume task only in case some player still holds card(s)
      if (g.getHand(0).current != 0 || g.getHand(1).current != 0 || g.getHand(2).current != 0)
      {
        restoreTurn(g, settings, table);
        new TaskGameResume(ferp, g, settings.isRostov(), service).execute();
      }
      else
        ferp.onGameResumeFinished(g);
    }
    else
      ferp.onGameResumeFinished(g);
  }

  private static void restoreLastTrickMenu(Game g, MenuItem lastTrick)
  {
    if (lastTrick != null)
      lastTrick.setEnabled(g.trick.last != 0);
  }

  private static void restoreFirstHand(Game g, TableView table)
  {
    if (g.type == Game.Type.UNKNOWN)
      table.showFirstHand(Game.next(g.player.dealer));
  }

  private static void restorePlayers(Game g, Settings settings, TableView table, boolean moving)
  {
    for (Player p : g.players())
    {
      table.showPlayerCards(g, settings, p);

      Game.BidData bid = g.getBid(p.id());

      if (bid.visible && bid.current != null)
        table.showBid(p, bid, false);

      // assign correct number of tricks for a player to resolve transient state/mode resuming
      //if (moving)
      //  g.setTricks(p.id(), g.trick.tricks(p.id(), g.trump()));

      table.setTrickCount(p.id(), g.getTricks(p.id()));
    }
  }

  private static void restoreTalon(Game g, Settings settings, TableView table)
  {
    table.setTalon(g.talon());

    for (int i = 0; i < Game.TALON_SIZE; ++i)
      switch (g.mode().getTalonCardState(g, settings, i))
      {
        case FACE_DOWN:
          table.closeTalon(i);
          break;

        case FACE_UP:
          table.openTalon(i);
          break;

        case HIDDEN:
          table.hideTalon(i);
          break;
      }
  }

  private static void restoreMisere(Game g, Settings settings, TableView table)
  {
    if (g.bid != null && g.bid.isMisere() && g.declarer() != g.human())
    {
      table.showMisereDesk(g, settings, g.getDeclarerHand().initial | g.getTalonHash(0) | g.getTalonHash(1), settings.isLandscape());

      for (int t : g.trick.list())
        markMisereDesk(g, table, t);

      if (g.trick.current != 0)
        markMisereDesk(g, table, g.trick.current);
    }
  }

  private static void markMisereDesk(Game g, TableView table, int trick)
  {
    Card c = Trick.card(trick, g.declarer());

    if (c != null)
      table.markMisereDesk(c);
  }

  private static void restoreTrick(Game g, TableView table)
  {
    if (g.trick.current != 0)
      table.showTrick(g.trick.current);

    // assign correct hand and current player to resolve transient state/mode resuming
    while (g.hand < Trick.size(g.trick.current))
    {
      ++g.hand;
      g.player.current = Game.next(g.player.current);
    }
  }

  private static void restoreTurn(Game g, Settings settings, TableView table)
  {
    Player mover = ((Moving)g.mode()).mover(g, settings, g.player.current);

    if (mover == g.human() && g.type != Game.Type.UNKNOWN)
      table.showTurn(g.player.current);
  }
}